<!doctype html>
<html lang="zh-CN">
<head>

    <meta charset="utf-8">
    <meta name="generator" content="Hugo 0.74.1" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>把flutter项目作为aar添加到已有的Android工程上 | caijinglong的博客</title>
    <meta property="og:title" content="把flutter项目作为aar添加到已有的Android工程上 - caijinglong的博客">
    <meta property="og:type" content="article">
        
    <meta property="article:published_time" content="2019-06-14T09:06:24&#43;08:00">
        
        
    <meta property="article:modified_time" content="2019-06-14T09:06:24&#43;08:00">
        
    <meta name="Keywords" content="golang,go语言,flutter,caijinglong,java,android,博客,项目管理,python,软件架构,公众号,小程序">
    <meta name="description" content="把flutter项目作为aar添加到已有的Android工程上">
        
    <meta name="author" content="caijinglong">
    <meta property="og:url" content="http://www.kikt.top/posts/flutter/exists/android-as-aar-to-maven/">
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">

    <link rel="stylesheet" href="/css/normalize.css">
    
        <link rel="stylesheet" href="/css/prism.css">
    
    <link rel="stylesheet" href="/css/style.css">
    <script type="text/javascript" src="//cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>

    

   
    <script>
        (function(){
            var bp = document.createElement('script');
            var curProtocol = window.location.protocol.split(':')[0];
            if (curProtocol === 'https') {
                bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
            }
            else {
                bp.src = 'http://push.zhanzhang.baidu.com/push.js';
            }
            var s = document.getElementsByTagName("script")[0];
            s.parentNode.insertBefore(bp, s);
        })();
    </script>

    
    
</head>

<body>
<header id="header" class="clearfix">
    <div class="container">
        <div class="col-group">
            <div class="site-name ">
                
                    <a id="logo" href="http://www.kikt.top">
                        caijinglong的博客
                    </a>
                
                <p class="description">Android/Flutter开发者，对于golang/python/ios/java 均有所了解</p>
            </div>
            <div>
                <nav id="nav-menu" class="clearfix">
                    <a class="" href="http://www.kikt.top">首页</a>
                    
                    <a  href="http://www.kikt.top/archives/" title="归档">归档</a>
                    
                    <a  href="http://www.kikt.top/contact/" title="接单">接单</a>
                    
                    <a  href="http://www.kikt.top/about/" title="关于">关于</a>
                    
                </nav>
            </div>
        </div>
    </div>
</header>


<div id="body">
    <div class="container">
        <div class="col-group">

            <div class="col-8" id="main">
                <div class="res-cons">
                    <article class="post">
                        <header>
                            <h1 class="post-title">把flutter项目作为aar添加到已有的Android工程上</h1>
                        </header>
                        <date class="post-meta meta-date">
                            2019年6月14日
                        </date>
                        
                        <div class="post-meta meta-category">
                            |
                            
                                <a href="http://www.kikt.top/categories/flutter">flutter</a>
                            
                                <a href="http://www.kikt.top/categories/android">android</a>
                            
                        </div>
                        
                        
                        <div class="post-meta">
                            <span id="busuanzi_container_page_pv">|<span id="busuanzi_value_page_pv"></span><span> 阅读</span></span>
                        </div>
                        
                        <div class="post-content">
                            <p>对于已有工程想要尝鲜 Flutter, 很多公司给出了最佳实践方案, android 中是使用 aar 加入项目中, 这样原生开发对于 flutter 环境就没有要求了, 只要 flutter 打包后上传 maven 即可, 但是这部分的过程坑很多, 后面我会再补充这种方案</p>
<p>我也摸索了一个实践方案, 将所有项目的 aar 由 flutter 方打包 aar 后将 aar 置入某一个固定位置 ,并置入一个 git 库管理, 然后 android 原生方直接 pull 后引入项目即可</p>
<p>高能预警: 本篇会结合 flutter, android, aar, gradle, maven, docker 的知识来完成所有的步骤</p>
<p>并不是每一个都会详细说明, 如果有不明白的可以在 <a href="https://www.kikt.top">https://www.kikt.top</a> 的本文下面留言, 我会更新文章或给予解答, 其他渠道的可能不会有时间看</p>
<ul>
<li><a href="#%e5%bc%80%e5%8f%91%e7%8e%af%e5%a2%83">开发环境</a>
<ul>
<li><a href="#%e6%9c%ac%e4%ba%ba%e8%ae%be%e5%a4%87%e7%8e%af%e5%a2%83">本人设备环境</a></li>
<li><a href="#%e9%a2%84%e8%ae%a1%e9%9c%80%e8%a6%81%e7%9a%84%e7%8e%af%e5%a2%83">预计需要的环境</a></li>
</ul>
</li>
<li><a href="#flutter">flutter</a>
<ul>
<li><a href="#%e5%88%9b%e5%bb%ba-flutter-module">创建 flutter module</a></li>
</ul>
</li>
<li><a href="#maven-%e7%9a%84%e5%a4%84%e7%90%86%e6%96%b9%e5%bc%8f%e7%9c%8b%e7%9c%8b%e5%b0%b1%e8%a1%8c%e4%bd%9c%e4%b8%ba%e9%94%99%e8%af%af%e5%b0%9d%e8%af%95%e7%9a%84%e6%ad%a5%e9%aa%a4">maven 的处理方式(看看就行,作为错误尝试的步骤)</a>
<ul>
<li><a href="#%e9%85%8d%e7%bd%ae">配置</a></li>
<li><a href="#%e8%bf%90%e8%a1%8c">运行</a></li>
<li><a href="#%e4%b8%8a%e4%bc%a0-aar">上传 aar</a>
<ul>
<li><a href="#%e4%bd%bf%e7%94%a8-gradle-%e4%b8%8a%e4%bc%a0-aar">使用 gradle 上传 aar</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#android-%e9%a1%b9%e7%9b%aehost">Android 项目(host)</a>
<ul>
<li><a href="#%e6%96%b0%e5%bb%ba%e9%a1%b9%e7%9b%ae">新建项目</a></li>
<li><a href="#%e5%bc%95%e5%85%a5-maven-%e4%be%9d%e8%b5%96">引入 maven 依赖</a>
<ul>
<li><a href="#%e6%b7%bb%e5%8a%a0%e4%bb%93%e5%ba%93">添加仓库</a></li>
</ul>
</li>
<li><a href="#%e7%bc%96%e7%a0%81">编码</a></li>
<li><a href="#%e8%bf%90%e8%a1%8c%e9%a1%b9%e7%9b%ae">运行项目</a></li>
<li><a href="#%e5%9c%a8-flutter-%e4%b8%ad%e6%b7%bb%e5%8a%a0%e5%b8%a6%e6%9c%89%e5%8e%9f%e7%94%9f%e5%8a%9f%e8%83%bd%e7%9a%84%e5%ba%93">在 flutter 中添加带有原生功能的库</a>
<ul>
<li><a href="#%e5%9c%a8-flutter-%e4%b8%ad%e6%b7%bb%e5%8a%a0%e5%ba%93">在 flutter 中添加库</a></li>
<li><a href="#%e4%b8%8a%e4%bc%a0%e6%96%b0%e7%89%88%e6%9c%ac%e7%9a%84-aar">上传新版本的 aar</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#%e6%80%9d%e8%80%83%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88">思考解决方案</a>
<ul>
<li><a href="#fat-aar">fat-aar</a></li>
<li><a href="#flutter-%e7%9a%84%e6%8f%92%e4%bb%b6%e5%ba%93%e4%b8%8a%e4%bc%a0%e8%87%b3-maven">flutter 的插件库上传至 maven</a></li>
</ul>
</li>
<li><a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88-%e4%bd%bf%e7%94%a8-aar-%e5%92%8c-git-%e7%ae%a1%e7%90%86">解决方案-使用 aar 和 git 管理</a>
<ul>
<li><a href="#%e5%a4%84%e7%90%86-flutter-%e7%ab%af">处理 flutter 端</a></li>
<li><a href="#%e6%96%b0%e5%bb%ba%e4%b8%80%e4%b8%aa%e7%9b%ae%e5%bd%95%e7%94%a8%e4%ba%8e%e5%ad%98%e6%94%be-aar">新建一个目录用于存放 aar</a></li>
<li><a href="#%e4%bf%ae%e6%94%b9-android-%e4%b8%bb%e5%b7%a5%e7%a8%8b">修改 android 主工程</a></li>
</ul>
</li>
<li><a href="#%e6%80%bb%e7%bb%93%e4%b8%80%e4%b8%8b%e6%89%80%e6%9c%89%e4%bf%ae%e6%94%b9">总结一下所有修改</a>
<ul>
<li><a href="#dart-%e8%84%9a%e6%9c%ac">dart 脚本</a></li>
<li><a href="#%e5%8e%9f%e7%94%9f%e9%83%a8%e5%88%86%e4%bf%ae%e6%94%b9">原生部分修改</a></li>
<li><a href="#%e8%bf%90%e8%a1%8c%e8%84%9a%e6%9c%ac">运行脚本</a></li>
</ul>
</li>
<li><a href="#%e5%90%8e%e8%ae%b0">后记</a></li>
</ul>
<h2 id="开发环境">开发环境</h2>
<h3 id="本人设备环境">本人设备环境</h3>
<p>MacOS 10.13.6 (17G65)<br>
flutter: Flutter 1.5.4-hotfix.2 • channel stable</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">2019-10-25 更新说明: 这篇文章因为发布时效的原因, 当时还没有 <span style="color:#e6db74">`</span>$ flutter build aar<span style="color:#e6db74">`</span> 这个命令
所以本人并没有实测两个东西的优劣性
</code></pre></div><h3 id="预计需要的环境">预计需要的环境</h3>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">xcode
android sdk
gradle
android studio
flutter sdk
docker <span style="color:#75715e"># 这个</span>
</code></pre></div><p><strong>这些环境我默认你都有</strong>, 没有的话本篇不讲</p>
<p>windows 用户? 对不住, 自己找寻其中的差别吧&hellip;</p>
<h2 id="flutter">flutter</h2>
<h3 id="创建-flutter-module">创建 flutter module</h3>
<p>使用命令行创建:</p>
<p><code>$ flutter create -t module flutter_module</code></p>
<!-- raw HTML omitted -->
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">cd flutter_module
flutter build apk
</code></pre></div><p>这里理论上会生成一个 aar</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">tree .android/Flutter/build/outputs
.android/Flutter/build/outputs
├── aar
│   └── flutter-release.aar
└── logs
    └── manifest-merger-release-report.txt
</code></pre></div><p>嗯,就这个东西</p>
<p>我们其实可以直接把这个 aar 放在宿主中,然后通过配置 aar 本地引用来直接使用这个工程, 但是这样可能并不利于持续集成</p>
<p>所以我们要用到 maven 这个利器</p>
<p>ps: 这里有个坑, 就是纯 flutter 项目可以, 但是如果你的 flutter 项目包含了对于第三方项目的依赖, 则 aar 可能不会包含其他的内容, 我们放在最后面再想办法解决</p>
<h2 id="maven-的处理方式看看就行作为错误尝试的步骤">maven 的处理方式(看看就行,作为错误尝试的步骤)</h2>
<p>本篇主要讲的是 maven 的方式, 没有原生 plugin 的很简单, 但是有原生 plugin 的 flutter 步骤过于复杂, 最终没实现, 当然理论上肯定是可以实现的</p>
<p>因为本篇讲解的是本人解决 flutter 附着到已有工程的尝试,所以将放弃的过程也记录下来, <strong>如果你只是想看最终的实现方案可以跳过本篇和后续所有涉及到 maven 的步骤</strong></p>
<p>maven 是一个包管理工具</p>
<p>如果你公司有自己的私服, 则跳过这一章直接看下一章, 我这里只是使用 docker 创建一个 maven 私服环境</p>
<p>使用的镜像是 sonatype/nexus3</p>
<h3 id="配置">配置</h3>
<p>可选: <code>$ docker pull sonatype/nexus3</code></p>
<p>我比较熟悉的有两种方式:</p>
<blockquote>
<p>命令行直接运行</p>
</blockquote>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">docker run --name test_nexus -d -p 8099:8081 -v /Volumes/Evo512/docker/nexus/nexus-data:/nexus-data sonatype/nexus3
</code></pre></div><blockquote>
<p>使用 docker-compose</p>
</blockquote>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#66d9ef">version</span>: <span style="color:#e6db74">&#39;2&#39;</span>

<span style="color:#66d9ef">services</span>:
  <span style="color:#66d9ef">my-nexus</span>:
    <span style="color:#66d9ef">image</span>: sonatype/nexus3
    <span style="color:#66d9ef">ports</span>:
      - <span style="color:#ae81ff">8099</span>:<span style="color:#ae81ff">8081</span>
    <span style="color:#66d9ef">networks</span>:
      - nexus-net
    <span style="color:#66d9ef">volumes</span>:
      - /Volumes/Evo512/docker/nexus/nexus-data:/nexus-data

<span style="color:#66d9ef">networks</span>:
  <span style="color:#66d9ef">nexus-net</span>:
    <span style="color:#66d9ef">driver</span>: bridge
</code></pre></div><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">docker-compose -d up
</code></pre></div><p>使用 docker-compose 就是类似于配置文件的方式</p>
<h3 id="运行">运行</h3>
<p>在浏览器打开 http://localhost:8099</p>
<p>登录的用户名密码,默认是 admin admin123</p>
<p>点开 maven, 毛也没有</p>
<p><img src="https://dev.azure.com/cjlspy/844861b8-ee45-48a3-b430-b974684baaaa/_apis/git/repositories/bf4da1c1-1cfa-4f54-8a75-745cce2b737c/items?versionDescriptor%5Bversion%5D=master&amp;path=%2F20190614095229.png&amp;versionDescriptor%5BversionOptions%5D=0&amp;versionDescriptor%5BversionType%5D=0&amp;resolveLfs=true&amp;%24format=octetStream&amp;api-version=5.0" alt="20190614095229.png"></p>
<h3 id="上传-aar">上传 aar</h3>
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<h4 id="使用-gradle-上传-aar">使用 gradle 上传 aar</h4>
<p>使用 android studio 打开 flutter_module 下的.android 目录, 经过一顿同步得到的可能是这样的:
<img src="https://dev.azure.com/cjlspy/844861b8-ee45-48a3-b430-b974684baaaa/_apis/git/repositories/bf4da1c1-1cfa-4f54-8a75-745cce2b737c/items?versionDescriptor%5Bversion%5D=master&amp;path=%2F20190614111354.png&amp;versionDescriptor%5BversionOptions%5D=0&amp;versionDescriptor%5BversionType%5D=0&amp;resolveLfs=true&amp;%24format=octetStream&amp;api-version=5.0" alt="20190614111354.png">
一片空白毛都没有&hellip;</p>
<p>这时候请 close, 重新打开, 现在是这个鬼样子的</p>
<p><img src="https://dev.azure.com/cjlspy/844861b8-ee45-48a3-b430-b974684baaaa/_apis/git/repositories/bf4da1c1-1cfa-4f54-8a75-745cce2b737c/items?versionDescriptor%5Bversion%5D=master&amp;path=%2F20190614111457.png&amp;versionDescriptor%5BversionOptions%5D=0&amp;versionDescriptor%5BversionType%5D=0&amp;resolveLfs=true&amp;%24format=octetStream&amp;api-version=5.0" alt="20190614111457.png"></p>
<p>采用 project 视图模式</p>
<p><img src="https://dev.azure.com/cjlspy/844861b8-ee45-48a3-b430-b974684baaaa/_apis/git/repositories/bf4da1c1-1cfa-4f54-8a75-745cce2b737c/items?versionDescriptor%5Bversion%5D=master&amp;path=%2F20190614111535.png&amp;versionDescriptor%5BversionOptions%5D=0&amp;versionDescriptor%5BversionType%5D=0&amp;resolveLfs=true&amp;%24format=octetStream&amp;api-version=5.0" alt="20190614111535.png"></p>
<p>在.android 下增加一个 gradle 文件,名字自取</p>
<p>比如我的就叫 update_aar.gradle</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-groovy" data-lang="groovy">apply plugin: <span style="color:#e6db74">&#39;maven&#39;</span>

<span style="color:#66d9ef">def</span> GROUP <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;top.kikt.flutter_lib&#39;</span>
<span style="color:#66d9ef">def</span> ARTIFACT_ID <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;module_example&#39;</span>
<span style="color:#66d9ef">def</span> VERSION_NAME <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;1.0.0&#34;</span>

<span style="color:#66d9ef">def</span> SNAPSHOT_REPOSITORY_URL <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;http://localhost:8099/repository/maven-snapshots/&#39;</span>
<span style="color:#66d9ef">def</span> RELEASE_REPOSITORY_URL <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;http://localhost:8099/repository/maven-releases/&#39;</span>
<span style="color:#66d9ef">def</span> REPOSITORY_URL <span style="color:#f92672">=</span> VERSION_NAME<span style="color:#f92672">.</span><span style="color:#a6e22e">toUpperCase</span><span style="color:#f92672">().</span><span style="color:#a6e22e">endsWith</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;-SNAPSHOT&#34;</span><span style="color:#f92672">)</span> <span style="color:#f92672">?</span> SNAPSHOT_REPOSITORY_URL <span style="color:#f92672">:</span> RELEASE_REPOSITORY_URL


<span style="color:#66d9ef">def</span> NEXUS_USERNAME <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;admin&#39;</span>
<span style="color:#66d9ef">def</span> NEXUS_PASSWORD <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;admin123&#39;</span>

afterEvaluate <span style="color:#f92672">{</span> project <span style="color:#f92672">-&gt;</span>
    uploadArchives <span style="color:#f92672">{</span>
        repositories <span style="color:#f92672">{</span>
            mavenDeployer <span style="color:#f92672">{</span>
                pom<span style="color:#f92672">.</span><span style="color:#a6e22e">groupId</span> <span style="color:#f92672">=</span> GROUP
                pom<span style="color:#f92672">.</span><span style="color:#a6e22e">artifactId</span> <span style="color:#f92672">=</span> ARTIFACT_ID
                pom<span style="color:#f92672">.</span><span style="color:#a6e22e">version</span> <span style="color:#f92672">=</span> VERSION_NAME
                repository<span style="color:#f92672">(</span>url: REPOSITORY_URL<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
                    authentication<span style="color:#f92672">(</span>userName: NEXUS_USERNAME<span style="color:#f92672">,</span> password: NEXUS_PASSWORD<span style="color:#f92672">)</span>
                <span style="color:#f92672">}</span>
            <span style="color:#f92672">}</span>
        <span style="color:#f92672">}</span>
    <span style="color:#f92672">}</span>
    task <span style="color:#a6e22e">androidJavadocs</span><span style="color:#f92672">(</span>type: Javadoc<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
        source <span style="color:#f92672">=</span> android<span style="color:#f92672">.</span><span style="color:#a6e22e">sourceSets</span><span style="color:#f92672">.</span><span style="color:#a6e22e">main</span><span style="color:#f92672">.</span><span style="color:#a6e22e">java</span><span style="color:#f92672">.</span><span style="color:#a6e22e">srcDirs</span>
        classpath <span style="color:#f92672">+=</span> project<span style="color:#f92672">.</span><span style="color:#a6e22e">files</span><span style="color:#f92672">(</span>android<span style="color:#f92672">.</span><span style="color:#a6e22e">getBootClasspath</span><span style="color:#f92672">().</span><span style="color:#a6e22e">join</span><span style="color:#f92672">(</span>File<span style="color:#f92672">.</span><span style="color:#a6e22e">pathSeparator</span><span style="color:#f92672">))</span>
    <span style="color:#f92672">}</span>
    task <span style="color:#a6e22e">androidJavadocsJar</span><span style="color:#f92672">(</span>type: Jar<span style="color:#f92672">,</span> dependsOn: androidJavadocs<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
        classifier <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;javadoc&#39;</span>
        from androidJavadocs<span style="color:#f92672">.</span><span style="color:#a6e22e">destinationDir</span>
    <span style="color:#f92672">}</span>
    task <span style="color:#a6e22e">androidSourcesJar</span><span style="color:#f92672">(</span>type: Jar<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
        classifier <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;sources&#39;</span>
        from android<span style="color:#f92672">.</span><span style="color:#a6e22e">sourceSets</span><span style="color:#f92672">.</span><span style="color:#a6e22e">main</span><span style="color:#f92672">.</span><span style="color:#a6e22e">java</span><span style="color:#f92672">.</span><span style="color:#a6e22e">sourceFiles</span>
    <span style="color:#f92672">}</span>

    <span style="color:#75715e">//解决 JavaDoc 中文注释生成失败的问题
</span><span style="color:#75715e"></span>    tasks<span style="color:#f92672">.</span><span style="color:#a6e22e">withType</span><span style="color:#f92672">(</span>Javadoc<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
        options<span style="color:#f92672">.</span><span style="color:#a6e22e">addStringOption</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#39;Xdoclint:none&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;-quiet&#39;</span><span style="color:#f92672">)</span>
        options<span style="color:#f92672">.</span><span style="color:#a6e22e">addStringOption</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#39;encoding&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;UTF-8&#39;</span><span style="color:#f92672">)</span>
        options<span style="color:#f92672">.</span><span style="color:#a6e22e">addStringOption</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#39;charSet&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;UTF-8&#39;</span><span style="color:#f92672">)</span>
    <span style="color:#f92672">}</span>
    artifacts <span style="color:#f92672">{</span>
        archives androidSourcesJar
        archives androidJavadocsJar
    <span style="color:#f92672">}</span>
<span style="color:#f92672">}</span>
</code></pre></div><p>这个文件呢, 就是上传用的 gradle 文件, 来源于<a href="https://blog.csdn.net/zhijiandedaima/article/details/90779782">网络</a></p>
<p>前几个 def 要根据你的 maven 来修改, 包名, 端口, 用户名,密码</p>
<p>接着引入 gradle 文件到项目中</p>
<p>修改: <code>Flutter/build.gradle</code></p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-groovy" data-lang="groovy">android<span style="color:#f92672">{</span>
    <span style="color:#75715e">/// ....
</span><span style="color:#75715e"></span><span style="color:#f92672">}</span>

apply from: <span style="color:#e6db74">&#34;${rootDir.path}/update_aar.gradle&#34;</span>
</code></pre></div><p>按照下图点击
<img src="https://dev.azure.com/cjlspy/844861b8-ee45-48a3-b430-b974684baaaa/_apis/git/repositories/bf4da1c1-1cfa-4f54-8a75-745cce2b737c/items?versionDescriptor%5Bversion%5D=master&amp;path=%2F20190614115416.png&amp;versionDescriptor%5BversionOptions%5D=0&amp;versionDescriptor%5BversionType%5D=0&amp;resolveLfs=true&amp;%24format=octetStream&amp;api-version=5.0" alt="img"></p>
<p>可能会报错</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">11:58:23: Executing task <span style="color:#e6db74">&#39;uploadArchives&#39;</span>...

Executing tasks: <span style="color:#f92672">[</span>uploadArchives<span style="color:#f92672">]</span>


FAILURE: Build failed with an exception.

* Where:
Settings file <span style="color:#e6db74">&#39;/Volumes/Evo512/code/flutter/add_to_exists_android/flutter_module/.android/settings.gradle&#39;</span> line: <span style="color:#ae81ff">7</span>

* What went wrong:
A problem occurred evaluating settings <span style="color:#e6db74">&#39;android_generated&#39;</span>.
&gt; /Volumes/Evo512/code/flutter/add_to_exists_android/flutter_module/.android/Flutter/include_flutter.groovy <span style="color:#f92672">(</span>/Volumes/Evo512/code/flutter/add_to_exists_android/flutter_module/.android/Flutter/include_flutter.groovy<span style="color:#f92672">)</span>

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 0s
11:58:23: Task execution finished <span style="color:#e6db74">&#39;uploadArchives&#39;</span>.

</code></pre></div><p>似乎是由于路径不对的原因, 请使用如下的方式修改 setting.gradle:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-groovy" data-lang="groovy"><span style="color:#75715e">// Generated file. Do not edit.
</span><span style="color:#75715e"></span>include <span style="color:#e6db74">&#39;:app&#39;</span>

rootProject<span style="color:#f92672">.</span><span style="color:#a6e22e">name</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;android_generated&#39;</span>
setBinding<span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> Binding<span style="color:#f92672">([</span>gradle: <span style="color:#66d9ef">this</span><span style="color:#f92672">]))</span>
<span style="color:#75715e">//evaluate(new File(&#39;include_flutter.groovy&#39;))
</span><span style="color:#75715e"></span>evaluate<span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> File<span style="color:#f92672">(</span><span style="color:#e6db74">&#34;$rootDir.path/include_flutter.groovy&#34;</span><span style="color:#f92672">))</span>
</code></pre></div><p>同步 gradle 后</p>
<p>接着双击
<img src="https://dev.azure.com/cjlspy/844861b8-ee45-48a3-b430-b974684baaaa/_apis/git/repositories/bf4da1c1-1cfa-4f54-8a75-745cce2b737c/items?versionDescriptor%5Bversion%5D=master&amp;path=%2F20190614120303.png&amp;versionDescriptor%5BversionOptions%5D=0&amp;versionDescriptor%5BversionType%5D=0&amp;resolveLfs=true&amp;%24format=octetStream&amp;api-version=5.0" alt="20190614120303.png"></p>
<p>就可以上传成功了</p>
<p>然后打开 nexus 查看: http://localhost:8099/#browse/search/maven</p>
<p><img src="https://dev.azure.com/cjlspy/844861b8-ee45-48a3-b430-b974684baaaa/_apis/git/repositories/bf4da1c1-1cfa-4f54-8a75-745cce2b737c/items?versionDescriptor%5Bversion%5D=master&amp;path=%2F20190614130245.png&amp;versionDescriptor%5BversionOptions%5D=0&amp;versionDescriptor%5BversionType%5D=0&amp;resolveLfs=true&amp;%24format=octetStream&amp;api-version=5.0" alt="20190614130245.png"></p>
<p><img src="https://dev.azure.com/cjlspy/844861b8-ee45-48a3-b430-b974684baaaa/_apis/git/repositories/bf4da1c1-1cfa-4f54-8a75-745cce2b737c/items?versionDescriptor%5Bversion%5D=master&amp;path=%2F20190614130414.png&amp;versionDescriptor%5BversionOptions%5D=0&amp;versionDescriptor%5BversionType%5D=0&amp;resolveLfs=true&amp;%24format=octetStream&amp;api-version=5.0" alt="20190614130414.png">
有显示, 说明这个 aar 上传是成功的</p>
<p>后面再上传更改版本号即可</p>
<h2 id="android-项目host">Android 项目(host)</h2>
<h3 id="新建项目">新建项目</h3>
<p><img src="https://dev.azure.com/cjlspy/844861b8-ee45-48a3-b430-b974684baaaa/_apis/git/repositories/bf4da1c1-1cfa-4f54-8a75-745cce2b737c/items?versionDescriptor%5Bversion%5D=master&amp;path=%2F20190614105539.png&amp;versionDescriptor%5BversionOptions%5D=0&amp;versionDescriptor%5BversionType%5D=0&amp;resolveLfs=true&amp;%24format=octetStream&amp;api-version=5.0" alt="20190614105539.png"></p>
<h3 id="引入-maven-依赖">引入 maven 依赖</h3>
<h4 id="添加仓库">添加仓库</h4>
<p>根目录 build.gradle, 根据节点增加一个 maven 仓库:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-groovy" data-lang="groovy">allprojects <span style="color:#f92672">{</span>
    repositories <span style="color:#f92672">{</span>
        google<span style="color:#f92672">()</span>
        jcenter<span style="color:#f92672">()</span>
        maven <span style="color:#f92672">{</span>
            url <span style="color:#e6db74">&#39;http://localhost:8099/repository/maven-releases/&#39;</span>
        <span style="color:#f92672">}</span>
    <span style="color:#f92672">}</span>
<span style="color:#f92672">}</span>
</code></pre></div><p>引入库, 在 nexus 的管理界面里可以查看引用方式:</p>
<p><img src="https://dev.azure.com/cjlspy/844861b8-ee45-48a3-b430-b974684baaaa/_apis/git/repositories/bf4da1c1-1cfa-4f54-8a75-745cce2b737c/items?versionDescriptor%5Bversion%5D=master&amp;path=%2F20190614130617.png&amp;versionDescriptor%5BversionOptions%5D=0&amp;versionDescriptor%5BversionType%5D=0&amp;resolveLfs=true&amp;%24format=octetStream&amp;api-version=5.0" alt="20190614130617.png"></p>
<p>接着在<code>app/build.gradle</code>中修改</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-groovy" data-lang="groovy">
dependencies <span style="color:#f92672">{</span>
    <span style="color:#75715e">// ...
</span><span style="color:#75715e"></span>    implementation <span style="color:#e6db74">&#39;top.kikt.flutter_lib:module_example:1.0.0&#39;</span>
<span style="color:#f92672">}</span>

</code></pre></div><p>经过 sync 以后,使用 project 视图, 可以找到这个库:</p>
<p><img src="https://dev.azure.com/cjlspy/844861b8-ee45-48a3-b430-b974684baaaa/_apis/git/repositories/bf4da1c1-1cfa-4f54-8a75-745cce2b737c/items?versionDescriptor%5Bversion%5D=master&amp;path=%2F20190614131424.png&amp;versionDescriptor%5BversionOptions%5D=0&amp;versionDescriptor%5BversionType%5D=0&amp;resolveLfs=true&amp;%24format=octetStream&amp;api-version=5.0" alt="20190614131424.png"></p>
<h3 id="编码">编码</h3>
<p>新建 MyFlutterActivity.java</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#f92672">package</span> top.kikit.androidhost<span style="color:#f92672">;</span>

<span style="color:#f92672">import</span> android.os.Bundle<span style="color:#f92672">;</span>

<span style="color:#f92672">import</span> io.flutter.app.FlutterActivity<span style="color:#f92672">;</span>
<span style="color:#f92672">import</span> io.flutter.plugins.GeneratedPluginRegistrant<span style="color:#f92672">;</span>

<span style="color:#75715e">/// create 2019-06-14 by cai
</span><span style="color:#75715e"></span>
<span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">MyFlutterActivity</span> <span style="color:#66d9ef">extends</span> FlutterActivity <span style="color:#f92672">{</span>

    <span style="color:#a6e22e">@Override</span>
    <span style="color:#66d9ef">protected</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">onCreate</span><span style="color:#f92672">(</span>Bundle savedInstanceState<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
        <span style="color:#66d9ef">super</span><span style="color:#f92672">.</span><span style="color:#a6e22e">onCreate</span><span style="color:#f92672">(</span>savedInstanceState<span style="color:#f92672">);</span>
        GeneratedPluginRegistrant<span style="color:#f92672">.</span><span style="color:#a6e22e">registerWith</span><span style="color:#f92672">(</span><span style="color:#66d9ef">this</span><span style="color:#f92672">);</span>
    <span style="color:#f92672">}</span>
<span style="color:#f92672">}</span>

</code></pre></div><p>添加到清单文件</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-xml" data-lang="xml"><span style="color:#f92672">&lt;application&gt;</span>
    <span style="color:#f92672">&lt;activity</span> <span style="color:#a6e22e">android:name=</span><span style="color:#e6db74">&#34;.MyFlutterActivity&#34;</span> <span style="color:#f92672">/&gt;</span>
<span style="color:#f92672">&lt;/application&gt;</span>
</code></pre></div><p>修改 MainActivity.java</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart">package top.kikit.androidhost;

<span style="color:#66d9ef">import</span> android<span style="color:#960050;background-color:#1e0010">.</span>content<span style="color:#960050;background-color:#1e0010">.</span>Intent;
<span style="color:#66d9ef">import</span> android<span style="color:#960050;background-color:#1e0010">.</span>os<span style="color:#960050;background-color:#1e0010">.</span>Bundle;

<span style="color:#66d9ef">import</span> androidx<span style="color:#960050;background-color:#1e0010">.</span>appcompat<span style="color:#960050;background-color:#1e0010">.</span>app<span style="color:#960050;background-color:#1e0010">.</span>AppCompatActivity;

public <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">MainActivity</span> <span style="color:#66d9ef">extends</span> AppCompatActivity {

    <span style="color:#960050;background-color:#1e0010">@</span>Override
    protected <span style="color:#66d9ef">void</span> onCreate(Bundle savedInstanceState) {
        <span style="color:#66d9ef">super</span>.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Flutter.startInitialization(<span style="color:#66d9ef">this</span>.getApplicationContext());
        Intent intent <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Intent(<span style="color:#66d9ef">this</span>, MyFlutterActivity.class);
        startActivity(intent);
    }
}

</code></pre></div><p>这里模拟一进来直接进 FlutterActivity 的场景</p>
<p>建议你的 Android 同事在合适的时机调用 <code>Flutter.startInitialization(this.getApplicationContext());</code> 这个是官方给出的初始化 flutter 引擎的代码, 否则首屏可能会慢</p>
<h3 id="运行项目">运行项目</h3>
<p>初次运行可能会报错 提示一个 androidO 什么的玩意</p>
<p>两种方案</p>
<ol>
<li>minSDK 修改为 26, 这个简直不科学</li>
<li>在 app/build.gradle 下的 android 节点下增加这个代码</li>
</ol>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-groovy" data-lang="groovy">android<span style="color:#f92672">{</span>
    compileOptions <span style="color:#f92672">{</span>
        sourceCompatibility <span style="color:#ae81ff">1.8</span>
        targetCompatibility <span style="color:#ae81ff">1.8</span>
    <span style="color:#f92672">}</span>
<span style="color:#f92672">}</span>
</code></pre></div><p>将源码和目标代码等级都设置为 1.8</p>
<p>嗯 这里插一句, 我的 host 使用的是 androidX, 而 flutter 使用的是 android.support, 所以需要按照 androidX 的迁移流程修改一下, 如果你新建项目的时候勾选了 androidX, 则这里应该不用修改</p>
<p>androidX 的问题可以查看我的<a href="https://www.kikt.top/posts/flutter/migrate-android-x/">另一篇文章</a>, 虽然是 flutter 分类下的,但是对于普通 android 工程也适用</p>
<p>运行结果如下:
<img src="https://dev.azure.com/cjlspy/844861b8-ee45-48a3-b430-b974684baaaa/_apis/git/repositories/bf4da1c1-1cfa-4f54-8a75-745cce2b737c/items?versionDescriptor%5Bversion%5D=master&amp;path=%2F20190614133601.png&amp;versionDescriptor%5BversionOptions%5D=0&amp;versionDescriptor%5BversionType%5D=0&amp;resolveLfs=true&amp;%24format=octetStream&amp;api-version=5.0" alt="20190614133601.png"></p>
<h3 id="在-flutter-中添加带有原生功能的库">在 flutter 中添加带有原生功能的库</h3>
<p>这里注意!!!!!!, 请先备份前面几个文件<br>
这里注意!!!!!!, 请先备份前面几个文件<br>
这里注意!!!!!!, 请先备份前面几个文件<br>
这里注意!!!!!!, 请先备份前面几个文件<br>
这里注意!!!!!!, 请先备份前面几个文件<br>
这里注意!!!!!!, 请先备份前面几个文件<br>
这里注意!!!!!!, 请先备份前面几个文件<br>
这里注意!!!!!!, 请先备份前面几个文件</p>
<p>因为一旦 flutter packages get, 则 前面的文件就木有了</p>
<h4 id="在-flutter-中添加库">在 flutter 中添加库</h4>
<p>这里简单举例一下, 使用一个比较常用的<code>shared_preferences</code></p>
<p>修改 flutter 的 yaml 文件</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#66d9ef">dependencies</span>:
  <span style="color:#66d9ef">shared_preferences</span>: ^<span style="color:#ae81ff">0.5.3+1</span>
</code></pre></div><p><code>$ flutter packages get</code></p>
<p>这一步后, 之前的那几个文件没有了&hellip;</p>
<p>建议: 把 build.gradle 和 setting.gradle 复制到 module 级别的某个目录下, 比如叫 template</p>
<p>然后用脚本来做这个上传的事情</p>
<ol>
<li>复制模板到对应目录</li>
<li>通过环境变量设置 aar 的版本号</li>
<li>使用 gradle 命令来完成插件的调用</li>
</ol>
<h4 id="上传新版本的-aar">上传新版本的 aar</h4>
<p>修改版本号为 1.0.1</p>
<p>这里上传成功了</p>
<p>到 android host 中用了一下, 果不其然和网上的朋友们说的一样报错了</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">ERROR: Unable to resolve dependency <span style="color:#66d9ef">for</span> <span style="color:#e6db74">&#39;:app@debug/compileClasspath&#39;</span>: Could not resolve io.flutter.plugins.sharedpreferences:shared_preferences:1.0-SNAPSHOT.
Show Details
Affected Modules: app


ERROR: Unable to resolve dependency <span style="color:#66d9ef">for</span> <span style="color:#e6db74">&#39;:app@debugAndroidTest/compileClasspath&#39;</span>: Could not resolve io.flutter.plugins.sharedpreferences:shared_preferences:1.0-SNAPSHOT.
Show Details
Affected Modules: app


ERROR: Unable to resolve dependency <span style="color:#66d9ef">for</span> <span style="color:#e6db74">&#39;:app@debugUnitTest/compileClasspath&#39;</span>: Could not resolve io.flutter.plugins.sharedpreferences:shared_preferences:1.0-SNAPSHOT.
Show Details
Affected Modules: app

</code></pre></div><p>查看对应的 pom.xml(我这里是 1.0.2),道理是一样的</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-xml" data-lang="xml"><span style="color:#f92672">&lt;project</span> <span style="color:#a6e22e">xmlns=</span><span style="color:#e6db74">&#34;http://maven.apache.org/POM/4.0.0&#34;</span>
    <span style="color:#a6e22e">xmlns:xsi=</span><span style="color:#e6db74">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span> <span style="color:#a6e22e">xsi:schemaLocation=</span><span style="color:#e6db74">&#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;</span><span style="color:#f92672">&gt;</span>
    <span style="color:#f92672">&lt;modelVersion&gt;</span>4.0.0<span style="color:#f92672">&lt;/modelVersion&gt;</span>
    <span style="color:#f92672">&lt;groupId&gt;</span>top.kikt.flutter_lib<span style="color:#f92672">&lt;/groupId&gt;</span>
    <span style="color:#f92672">&lt;artifactId&gt;</span>module_example<span style="color:#f92672">&lt;/artifactId&gt;</span>
    <span style="color:#f92672">&lt;version&gt;</span>1.0.2<span style="color:#f92672">&lt;/version&gt;</span>
    <span style="color:#f92672">&lt;packaging&gt;</span>aar<span style="color:#f92672">&lt;/packaging&gt;</span>
    <span style="color:#f92672">&lt;dependencies&gt;</span>
        <span style="color:#f92672">&lt;dependency&gt;</span>
            <span style="color:#f92672">&lt;groupId&gt;</span>io.flutter.plugins.sharedpreferences<span style="color:#f92672">&lt;/groupId&gt;</span>
            <span style="color:#f92672">&lt;artifactId&gt;</span>shared_preferences<span style="color:#f92672">&lt;/artifactId&gt;</span>
            <span style="color:#f92672">&lt;version&gt;</span>1.0-SNAPSHOT<span style="color:#f92672">&lt;/version&gt;</span>
            <span style="color:#f92672">&lt;scope&gt;</span>compile<span style="color:#f92672">&lt;/scope&gt;</span>
        <span style="color:#f92672">&lt;/dependency&gt;</span>
        <span style="color:#f92672">&lt;dependency&gt;</span>
            <span style="color:#f92672">&lt;groupId&gt;</span>com.android.support<span style="color:#f92672">&lt;/groupId&gt;</span>
            <span style="color:#f92672">&lt;artifactId&gt;</span>support-v13<span style="color:#f92672">&lt;/artifactId&gt;</span>
            <span style="color:#f92672">&lt;version&gt;</span>27.1.1<span style="color:#f92672">&lt;/version&gt;</span>
            <span style="color:#f92672">&lt;scope&gt;</span>compile<span style="color:#f92672">&lt;/scope&gt;</span>
        <span style="color:#f92672">&lt;/dependency&gt;</span>
        <span style="color:#f92672">&lt;dependency&gt;</span>
            <span style="color:#f92672">&lt;groupId&gt;</span>com.android.support<span style="color:#f92672">&lt;/groupId&gt;</span>
            <span style="color:#f92672">&lt;artifactId&gt;</span>support-annotations<span style="color:#f92672">&lt;/artifactId&gt;</span>
            <span style="color:#f92672">&lt;version&gt;</span>27.1.1<span style="color:#f92672">&lt;/version&gt;</span>
            <span style="color:#f92672">&lt;scope&gt;</span>compile<span style="color:#f92672">&lt;/scope&gt;</span>
        <span style="color:#f92672">&lt;/dependency&gt;</span>
    <span style="color:#f92672">&lt;/dependencies&gt;</span>
<span style="color:#f92672">&lt;/project&gt;</span>
</code></pre></div><p>这里有一个 io.flutter.plugins.sharedpreferences 就是报错的元凶了</p>
<h2 id="思考解决方案">思考解决方案</h2>
<p>看到这里我感觉有如下的方案</p>
<ol>
<li>将所有文件打包到同一个 aar 库中, 然后再上传(也就是网上那个 fat-aar 的方案)</li>
<li>修改 flutter 打包脚本, 然后将中间的三方库产物(sp 插件)上传至私服 maven, flutter 项目使用 api 的方式依赖这些库, 完成 host=&gt;flutter=&gt;other plugin 的目的</li>
<li>不用 maven, 只用 aar</li>
</ol>
<p>个人第一感觉, 觉得第一个实施起来可能会简单一些, 先尝试一下</p>
<h3 id="fat-aar">fat-aar</h3>
<p>这个找到了两个项目:</p>
<p>一个 gradle 文件的方式: <a href="https://github.com/adwiv/android-fat-aar">https://github.com/adwiv/android-fat-aar</a></p>
<p>一个是 plugin 的方式: <a href="https://github.com/Vigi0303/fat-aar-plugin">https://github.com/Vigi0303/fat-aar-plugin</a></p>
<p>但是都要用到一个类似<code>embed</code>这样的关键字来替换 compile(api/implementation), 无奈找遍 gradle 没找到修改的地方, 只能暂时放弃</p>
<h3 id="flutter-的插件库上传至-maven">flutter 的插件库上传至 maven</h3>
<p>这个初始来看很可行.. 但仔细一想, 因为那个版本号的作祟, 需要改动的地方不算很少</p>
<p>每个插件包内的 gradle 文件都需要修改:</p>
<ol>
<li>修改 version 版本号,这个应该是可以通过 环境变量/gradle 命令 来指定为佳, 不能指定的话理论上和 pub 的版本号相同也可以, 如果是 git 依赖, 就用 ref, path 依赖就很比较难自动取了</li>
<li>上传脚本,这个要读取上面的版本号, 还要读取一个</li>
</ol>
<p>为什么要修改版本号呢? flutter 依赖的插件的版本号会被带到 aar 对应的 maven 库中的 pom.xml 文件中</p>
<p>这里要插一句: pom.xml 中依赖的版本号是定义在每个插件自己的 build.gradle 中的,如下面的连接那样</p>
<p>如下所示:
<a href="https://github.com/OpenFlutter/flutter_image_compress/blob/e841181d16df44b94c45e77ee1dcd36ebdc27905/android/build.gradle#L1-L2">https://github.com/OpenFlutter/flutter_image_compress/blob/e841181d16df44b94c45e77ee1dcd36ebdc27905/android/build.gradle#L1-L2</a></p>
<p><a href="https://github.com/flutter/plugins/blob/e9766e668b4a84ac526414e26981a23c661aff18/packages/shared_preferences/android/build.gradle#L14-L15">https://github.com/flutter/plugins/blob/e9766e668b4a84ac526414e26981a23c661aff18/packages/shared_preferences/android/build.gradle#L14-L15</a></p>
<p>我这里说需要修改的就是这个版本号,否则你上传 maven 的 flutter 库的版本号和插件的 maven 版本号没对上的话,依然会报错</p>
<p>修改版本号并上传需要遵循如下的步骤:</p>
<ol>
<li>读取本地<code>.flutter-plugins</code>文件的内容,将其中的版本号字段取出来</li>
<li>找到插件文件夹,替换掉版本号字段的内容</li>
<li>将上传插件的脚本复制至对应文件夹,并将版本号,group 名与插件统一</li>
<li>启动上传脚本</li>
<li>将对原生文件的修改内容还原</li>
</ol>
<p>为什么要做最后一步呢? 这种&quot;从远端&quot;镜像下来的东西,修改回去是一个好习惯, 因为修改了会破坏仓库本身版本的完整性</p>
<h2 id="解决方案-使用-aar-和-git-管理">解决方案-使用 aar 和 git 管理</h2>
<p>这个就是我开篇说的解决方案, 不使用 maven, 只是打包出 aar, 集中起来, 置入 git 仓库,如果有必要就打 tag 后 push 到远端, 方便根据版本来引用</p>
<p>然后作为 android 原生方, 在 project 的 gradle 中引入 aar 库即可, 当然如果你是大公司有自己的要求, 还是用上一种比较好</p>
<p>git 和 aar 引入也是很成熟的使用方案了, 无非就是如何拼接而已的问题, 何况这一步还可以通过 gradle 自动完成</p>
<h3 id="处理-flutter-端">处理 flutter 端</h3>
<p>这次使用 dart 来作为脚本, 毕竟 dart 语言对于 flutter 开发者来说会很熟悉, 当然这一步可以用任何你熟悉的方式,比如: shell/python 等等, 这一步的执行需要将 dart 放入环境变量中</p>
<p><code>build_module.dart</code>:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart"><span style="color:#66d9ef">import</span> <span style="color:#e6db74">&#39;dart:io&#39;</span>;

<span style="color:#66d9ef">var</span> outputDir <span style="color:#f92672">=</span> Directory(<span style="color:#e6db74">&#34;../output&#34;</span>);
<span style="color:#66d9ef">var</span> targetDir <span style="color:#f92672">=</span> Directory(<span style="color:#e6db74">&#34;../../flutter-aar&#34;</span>);

Future main() <span style="color:#66d9ef">async</span> {
  List<span style="color:#f92672">&lt;</span>AAR<span style="color:#f92672">&gt;</span> list <span style="color:#f92672">=</span> [];

  outputDir.deleteSync(recursive: <span style="color:#66d9ef">true</span>);
  outputDir.createSync(recursive: <span style="color:#66d9ef">true</span>);
  <span style="color:#66d9ef">var</span> file <span style="color:#f92672">=</span> File(<span style="color:#e6db74">&#34;../.flutter-plugins&#34;</span>);
  <span style="color:#66d9ef">var</span> plugins <span style="color:#f92672">=</span> file.readAsLinesSync();
  <span style="color:#66d9ef">for</span> (<span style="color:#66d9ef">var</span> value <span style="color:#66d9ef">in</span> plugins) {
    <span style="color:#66d9ef">if</span> (value.trim().isEmpty) {
      <span style="color:#66d9ef">continue</span>;
    }
    <span style="color:#66d9ef">var</span> splitArr <span style="color:#f92672">=</span> value.split(<span style="color:#e6db74">&#34;=&#34;</span>);
    <span style="color:#66d9ef">var</span> name <span style="color:#f92672">=</span> splitArr[<span style="color:#ae81ff">0</span>];
    <span style="color:#66d9ef">var</span> path <span style="color:#f92672">=</span> splitArr[<span style="color:#ae81ff">1</span>];

    <span style="color:#66d9ef">var</span> aar <span style="color:#f92672">=</span> handlePlugin(name, path);
    list.add(aar);
  }

  <span style="color:#66d9ef">var</span> aar <span style="color:#f92672">=</span> <span style="color:#66d9ef">await</span> handleFlutter();
  list.add(aar);

  handleAAR(list);
}

<span style="color:#66d9ef">void</span> handleAAR(List<span style="color:#f92672">&lt;</span>AAR<span style="color:#f92672">&gt;</span> list) {
  targetDir.deleteSync(recursive: <span style="color:#66d9ef">true</span>);
  targetDir.createSync();
  list.forEach((aar) {
    <span style="color:#66d9ef">var</span> targetPath <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>targetDir.path<span style="color:#e6db74">}</span><span style="color:#e6db74">/</span><span style="color:#e6db74">${</span>aar.aarName<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>;
    <span style="color:#66d9ef">var</span> targetFile <span style="color:#f92672">=</span> aar.file.copySync(targetPath);
    print(
        <span style="color:#e6db74">&#39;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">copy &#34;</span><span style="color:#e6db74">${</span>aar.file.absolute.path<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34; to &#34;</span><span style="color:#e6db74">${</span>targetFile.absolute.path<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;&#39;</span>);
  });
}

AAR handlePlugin(<span style="color:#66d9ef">String</span> name, <span style="color:#66d9ef">String</span> path) {
  <span style="color:#66d9ef">var</span> result <span style="color:#f92672">=</span> Process.runSync(<span style="color:#e6db74">&#34;./gradlew&#34;</span>, [<span style="color:#e6db74">&#34;</span><span style="color:#e6db74">$</span>name<span style="color:#e6db74">:assRel&#34;</span>],
      workingDirectory: <span style="color:#e6db74">&#34;../.android&#34;</span>);
  print(result.stdout);

  <span style="color:#66d9ef">var</span> aarFile <span style="color:#f92672">=</span> File(<span style="color:#e6db74">&#34;</span><span style="color:#e6db74">$</span>path<span style="color:#e6db74">/android/build/outputs/aar/</span><span style="color:#e6db74">$</span>name<span style="color:#e6db74">-release.aar&#34;</span>);
  <span style="color:#66d9ef">var</span> aarName <span style="color:#f92672">=</span> aarFile.path.split(<span style="color:#e6db74">&#34;/&#34;</span>).last;
  <span style="color:#66d9ef">var</span> pathName <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>outputDir.path<span style="color:#e6db74">}</span><span style="color:#e6db74">/</span><span style="color:#e6db74">$</span>aarName<span style="color:#e6db74">&#34;</span>;
  <span style="color:#66d9ef">var</span> targetFile <span style="color:#f92672">=</span> aarFile.copySync(pathName);
  <span style="color:#66d9ef">return</span> AAR()
    ..file <span style="color:#f92672">=</span> targetFile
    ..aarName <span style="color:#f92672">=</span> aarName;
}

Future<span style="color:#f92672">&lt;</span>AAR<span style="color:#f92672">&gt;</span> handleFlutter() <span style="color:#66d9ef">async</span> {
  <span style="color:#66d9ef">var</span> processResult <span style="color:#f92672">=</span> <span style="color:#66d9ef">await</span> Process.run(
    <span style="color:#e6db74">&#34;flutter&#34;</span>,
    [<span style="color:#e6db74">&#34;build&#34;</span>, <span style="color:#e6db74">&#34;apk&#34;</span>],
    workingDirectory: <span style="color:#e6db74">&#34;..&#34;</span>,
    runInShell: <span style="color:#66d9ef">true</span>,
  );

  print(processResult.stdout);

  <span style="color:#66d9ef">var</span> name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;flutter-release.aar&#34;</span>;

  <span style="color:#66d9ef">var</span> file <span style="color:#f92672">=</span> File(<span style="color:#e6db74">&#34;../.android/Flutter/build/outputs/aar/flutter-release.aar&#34;</span>);
  <span style="color:#66d9ef">var</span> target <span style="color:#f92672">=</span> file.copySync(<span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>outputDir.path<span style="color:#e6db74">}</span><span style="color:#e6db74">/</span><span style="color:#e6db74">$</span>name<span style="color:#e6db74">&#34;</span>);

  <span style="color:#66d9ef">return</span> AAR()
    ..file <span style="color:#f92672">=</span> target
    ..aarName <span style="color:#f92672">=</span> name;
}

<span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AAR</span> {
  <span style="color:#66d9ef">String</span> aarName;
  File file;

  <span style="color:#66d9ef">String</span> <span style="color:#66d9ef">get</span> noExtensionAarName <span style="color:#f92672">=&gt;</span> aarName.split(<span style="color:#e6db74">&#34;.&#34;</span>).first;

  <span style="color:#960050;background-color:#1e0010">@</span>override
  <span style="color:#66d9ef">String</span> toString() {
    <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#39;AAR{aarName: </span><span style="color:#e6db74">$</span>aarName<span style="color:#e6db74">, file: </span><span style="color:#e6db74">$</span>file<span style="color:#e6db74">, noExtensionAarName: </span><span style="color:#e6db74">$</span>noExtensionAarName<span style="color:#e6db74">}&#39;</span>;
  }
}
</code></pre></div><p>大概解释下脚本的功能:</p>
<ol>
<li>处理<code>.flutter-plugins</code>文件,获取 android 所在目录</li>
<li>执行<code>flutter/.android</code>下的 gradle 命令来生成 aar</li>
<li>根据插件所在目录来获取 aar 文件</li>
<li>打包 flutter 本身的 aar, 这一步因为一些资源的原因, 直接使用 flutter build apk, 会完成所有的中间产物的生成</li>
<li>将 插件和 flutter 的 aar 文件复制到 output/flutter-aar 文件夹下</li>
</ol>
<p>output 文件夹就是我们作为 git 依赖使用的文件夹, 这个文件夹</p>
<p>命令: <code>$ dart build_aar.dart</code></p>
<h3 id="新建一个目录用于存放-aar">新建一个目录用于存放 aar</h3>
<p>因为 git submodule 的管理方式对于新手不友好, 所以使用更简单一点的方案管理</p>
<p>新建一个目录,把所有的 aar 文件都放在一起
(我的示例代码是放在一个仓库里的, 不过是同级目录)</p>
<p>当前的目录结构是这样的:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">tree -L <span style="color:#ae81ff">2</span>
.
├── README.md
├── android-host
│   ├── android-host.iml
│   ├── app
│   ├── build
│   ├── build.gradle
│   ├── gradle
│   ├── gradle.properties
│   ├── gradlew
│   ├── gradlew.bat
│   ├── local.properties
│   └── settings.gradle
├── flutter-aar
│   ├── flutter-release.aar
│   └── shared_preferences-release.aar
└── flutter_module
    ├── README.md
    ├── build
    ├── flutter_module.iml
    ├── flutter_module_android.iml
    ├── lib
    ├── output
    ├── pubspec.lock
    ├── pubspec.yaml
    ├── shell
    ├── template
    └── test

</code></pre></div><p>这样分级的好处是仓库权限的分级:</p>
<p>android 组允许访问 android-host 和 flutter-aar</p>
<p>flutter 组允许访问 flutter_module 和 flutter-aar</p>
<p>我示例代码是一个仓库, 但实际上对于项目来说应该是 3 个仓库为佳</p>
<h3 id="修改-android-主工程">修改 android 主工程</h3>
<p>build.gradle:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-groovy" data-lang="groovy">
<span style="color:#66d9ef">def</span> aarDir <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;${rootProject.projectDir.path}/../flutter-aar&#34;</span>

repositories <span style="color:#f92672">{</span>
    flatDir <span style="color:#f92672">{</span>
        dirs aarDir
    <span style="color:#f92672">}</span>
<span style="color:#f92672">}</span>

dependencies <span style="color:#f92672">{</span>
    implementation <span style="color:#a6e22e">fileTree</span><span style="color:#f92672">(</span>dir: <span style="color:#e6db74">&#39;libs&#39;</span><span style="color:#f92672">,</span> include: <span style="color:#f92672">[</span><span style="color:#e6db74">&#39;*.jar&#39;</span><span style="color:#f92672">])</span>
    implementation <span style="color:#e6db74">&#39;androidx.appcompat:appcompat:1.0.2&#39;</span>
    implementation <span style="color:#e6db74">&#39;androidx.constraintlayout:constraintlayout:1.1.3&#39;</span>
    testImplementation <span style="color:#e6db74">&#39;junit:junit:4.12&#39;</span>
    androidTestImplementation <span style="color:#e6db74">&#39;androidx.test:runner:1.2.0&#39;</span>
    androidTestImplementation <span style="color:#e6db74">&#39;androidx.test.espresso:espresso-core:3.2.0&#39;</span>

    <span style="color:#66d9ef">def</span> file <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> File<span style="color:#f92672">(</span>aarDir<span style="color:#f92672">)</span>
    file<span style="color:#f92672">.</span><span style="color:#a6e22e">listFiles</span><span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> FilenameFilter<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
        <span style="color:#a6e22e">@Override</span>
        <span style="color:#66d9ef">boolean</span> <span style="color:#a6e22e">accept</span><span style="color:#f92672">(</span>File dir<span style="color:#f92672">,</span> String name<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
            <span style="color:#66d9ef">return</span> name<span style="color:#f92672">.</span><span style="color:#a6e22e">endsWith</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;aar&#34;</span><span style="color:#f92672">)</span>
        <span style="color:#f92672">}</span>
    <span style="color:#f92672">}).</span><span style="color:#a6e22e">each</span> <span style="color:#f92672">{</span> f <span style="color:#f92672">-&gt;</span>
        <span style="color:#66d9ef">def</span> aar <span style="color:#f92672">=</span> f<span style="color:#f92672">.</span><span style="color:#a6e22e">name</span><span style="color:#f92672">.</span><span style="color:#a6e22e">split</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;\\.&#34;</span><span style="color:#f92672">).</span><span style="color:#a6e22e">first</span><span style="color:#f92672">()</span>
        println<span style="color:#f92672">(</span><span style="color:#e6db74">&#34;f.name = ${f.name} , aar = $aar&#34;</span><span style="color:#f92672">)</span>
        api<span style="color:#f92672">(</span>name: f<span style="color:#f92672">.</span><span style="color:#a6e22e">name</span><span style="color:#f92672">.</span><span style="color:#a6e22e">split</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;\\.&#34;</span><span style="color:#f92672">).</span><span style="color:#a6e22e">first</span><span style="color:#f92672">(),</span> ext: <span style="color:#e6db74">&#39;aar&#39;</span><span style="color:#f92672">)</span>
    <span style="color:#f92672">}</span>
<span style="color:#f92672">}</span>

</code></pre></div><p>这样的情况下这个目录就完成了对于所有 aar 文件的引用</p>
<h2 id="总结一下所有修改">总结一下所有修改</h2>
<h3 id="dart-脚本">dart 脚本</h3>
<ol>
<li>复制我提供的仓库下<code>flutter_module/shell/build_module.dart</code>到你的 flutter 下的 shell 目录</li>
<li>修改这个 dart 脚本中的 targetDir 目录到任何你想要的目录(无论是直接到原生还是到单独仓库内)</li>
</ol>
<h3 id="原生部分修改">原生部分修改</h3>
<p>修改 build.gradle 加入对于 aar 的引用</p>
<p>这里使用仓库还是直接在原生工程里看你们项目管理的要求</p>
<p>这一步可以从原生项目的 app/build.gradle 看到所有修改</p>
<h3 id="运行脚本">运行脚本</h3>
<p>总结一下我的运行步骤:</p>
<ol>
<li>命令行在根目录下执行 <code>cd flutter_module/shell &amp;&amp; dart build_module.dart</code></li>
<li>运行 android 项目</li>
</ol>
<p>建议的步骤如下:</p>
<p>对于 <strong>flutter</strong> 开发者来说:</p>
<ol>
<li><code>cd flutter_project/shell &amp;&amp; dart build_module.dart</code></li>
<li><code>cd android-aar</code></li>
<li>操作 git 仓库,上传 aar</li>
</ol>
<p>对于<strong>安卓</strong>原生来说:</p>
<ol>
<li><code>$ cd android-aar</code></li>
<li><code>$ git pull</code></li>
<li>运行项目</li>
</ol>
<h2 id="后记">后记</h2>
<p>本篇详细介绍了我是如何解决 flutter 添加到已有工程的方案, 虽然字数多, 但是实际引入并不复杂</p>
<p>可能有遗漏, 有不清楚的请在<a href="https://kikt.top">官方 blog</a> 下评论留言, csdn 仅作为文章的同步发布平台, 评论可能没有时间看</p>
<p>嗯,仓库在这里: <a href="https://gitee.com/kikt/add_flutter_to_exists_android">gitee</a></p>
<p>以上</p>

                        </div>

                        

<div class="post-archive">
    <h2>See Also</h2>
    <ul class="listing">
        
        <li><a href="/posts/flutter/android/flutter.gradle/">Flutter flutter.gradle分析</a></li>
        
        <li><a href="/posts/flutter/dart/generators/">dart中的生成器函数</a></li>
        
        <li><a href="/posts/flutter/android/profile-1/">在Profile下分析android内存占用</a></li>
        
        <li><a href="/posts/flutter/exists/android/">在原 Android 工程的基础上构建一个flutter工程</a></li>
        
        <li><a href="/posts/flutter/android/finish-activity/">Finish FlutterActivity 源码解析</a></li>
        
    </ul>
</div>


                        <div class="post-meta meta-tags">
                            
                            <ul class="clearfix">
                                
                                <li><a href="http://www.kikt.top/tags/android">android</a></li>
                                
                                <li><a href="http://www.kikt.top/tags/aar">aar</a></li>
                                
                                <li><a href="http://www.kikt.top/tags/gradle">gradle</a></li>
                                
                                <li><a href="http://www.kikt.top/tags/maven">maven</a></li>
                                
                                <li><a href="http://www.kikt.top/tags/flutter">flutter</a></li>
                                
                                <li><a href="http://www.kikt.top/tags/docker">docker</a></li>
                                
                                <li><a href="http://www.kikt.top/tags/%E5%B7%B2%E6%9C%89%E9%A1%B9%E7%9B%AE">已有项目</a></li>
                                
                            </ul>
                            
                        </div>
                    </article>
                    
    

    
    
    <div class="post bg-white">
      <script src="https://utteranc.es/client.js"
            repo= "caijinglong/kikt-blog-comment"
            issue-term="pathname"
            theme="github-light"
            crossorigin="anonymous"
            async>
      </script>
    </div>
    
                </div>
            </div>
            <div id="secondary">
    <section class="widget">
        <form id="search" action="//www.google.com/search" method="get" accept-charset="utf-8" target="_blank" _lpchecked="1">
      
      <input type="text" name="q" maxlength="20" placeholder="Search">
      <input type="hidden" name="sitesearch" value="http://www.kikt.top">
      <button type="submit" class="submit icon-search"></button>
</form>
    </section>
    
    <section class="widget">
        <h3 class="widget-title">最近文章</h3>
<ul class="widget-list">
    
    <li>
        <a href="http://www.kikt.top/posts/java/crack/crack1/" title="使用javassist,修改jar包方法实现">使用javassist,修改jar包方法实现</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/posts/github/actions/create/" title="Github action 的开发到发布">Github action 的开发到发布</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/posts/flutter/jenkins&#43;fastlane/" title="flutter Jenkins&#43;fastlane 自动化打测试包, 并上传蒲公英">flutter Jenkins&#43;fastlane 自动化打测试包, 并上传蒲公英</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/posts/go/compile-for-android/" title="编译 go 源码为 android 动态库(so)">编译 go 源码为 android 动态库(so)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/posts/flutter/focusnode-2/" title="Flutter FocusNode 焦点那点事-(二)">Flutter FocusNode 焦点那点事-(二)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/posts/flutter/focusnode-1/" title="Flutter FocusNode 焦点那点事-(一)">Flutter FocusNode 焦点那点事-(一)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/posts/server/caddy/cros_for_local_dev/" title="用 Caddy 解决 web 开发中本地跨域的问题">用 Caddy 解决 web 开发中本地跨域的问题</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/posts/flutter/route/navigator-helper2/" title="Navigator Helper2">Navigator Helper2</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/posts/flutter/grey-app/" title="flutter 怎么实现app整体灰度">flutter 怎么实现app整体灰度</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/posts/flutter/plugin/flutter-sdk-import-aar/" title="Flutter 插件开发之引入aar到安卓部分 并使用本地maven">Flutter 插件开发之引入aar到安卓部分 并使用本地maven</a>
    </li>
    
</ul>
    </section>

    

    <section class="widget">
        <h3 class="widget-title">分类</h3>
<ul class="widget-list">
    
    <li>
        <a href="http://www.kikt.top/categories/android/">android(25)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/caddy/">caddy(1)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/dart/">dart(5)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/docker/">docker(3)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/flutter/">flutter(60)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/github/">github(3)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/go/">go(1)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/golang/">golang(1)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/iOS/">iOS(6)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/ios/">ios(1)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/java/">java(6)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/jetbrains/">jetbrains(1)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/other/">other(3)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/python/">python(1)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/server/">server(5)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/spring/">spring(3)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/tools/">tools(1)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/%E6%9D%82%E9%A1%B9/">杂项(1)</a>
    </li>
    
    <li>
        <a href="http://www.kikt.top/categories/%E6%B6%82%E9%B8%A6/">涂鸦(1)</a>
    </li>
    
</ul>
    </section>

    <section class="widget">
        <h3 class="widget-title">标签</h3>
<div class="tagcloud">
    
    <a href="http://www.kikt.top/tags/10/">10</a>
    
    <a href="http://www.kikt.top/tags/2.3/">2.3</a>
    
    <a href="http://www.kikt.top/tags/Clipboard/">Clipboard</a>
    
    <a href="http://www.kikt.top/tags/Javassist/">Javassist</a>
    
    <a href="http://www.kikt.top/tags/Migrate/">Migrate</a>
    
    <a href="http://www.kikt.top/tags/aar/">aar</a>
    
    <a href="http://www.kikt.top/tags/actions/">actions</a>
    
    <a href="http://www.kikt.top/tags/aidl/">aidl</a>
    
    <a href="http://www.kikt.top/tags/android/">android</a>
    
    <a href="http://www.kikt.top/tags/androidQ/">androidQ</a>
    
    <a href="http://www.kikt.top/tags/androidX/">androidX</a>
    
    <a href="http://www.kikt.top/tags/apk/">apk</a>
    
    <a href="http://www.kikt.top/tags/app/">app</a>
    
    <a href="http://www.kikt.top/tags/appcode/">appcode</a>
    
    <a href="http://www.kikt.top/tags/azure/">azure</a>
    
    <a href="http://www.kikt.top/tags/ble/">ble</a>
    
    <a href="http://www.kikt.top/tags/bottomsheet/">bottomsheet</a>
    
    <a href="http://www.kikt.top/tags/butterknife/">butterknife</a>
    
    <a href="http://www.kikt.top/tags/c/">c</a>
    
    <a href="http://www.kikt.top/tags/caddy/">caddy</a>
    
    <a href="http://www.kikt.top/tags/camera/">camera</a>
    
    <a href="http://www.kikt.top/tags/cameraX/">cameraX</a>
    
    <a href="http://www.kikt.top/tags/channel/">channel</a>
    
    <a href="http://www.kikt.top/tags/cocoapods/">cocoapods</a>
    
    <a href="http://www.kikt.top/tags/cupertino/">cupertino</a>
    
    <a href="http://www.kikt.top/tags/dart/">dart</a>
    
    <a href="http://www.kikt.top/tags/dart-2.6/">dart-2.6</a>
    
    <a href="http://www.kikt.top/tags/desktop/">desktop</a>
    
    <a href="http://www.kikt.top/tags/dialog/">dialog</a>
    
    <a href="http://www.kikt.top/tags/dmg/">dmg</a>
    
    <a href="http://www.kikt.top/tags/doc/">doc</a>
    
    <a href="http://www.kikt.top/tags/docker/">docker</a>
    
    <a href="http://www.kikt.top/tags/docker-compose/">docker-compose</a>
    
    <a href="http://www.kikt.top/tags/excel/">excel</a>
    
    <a href="http://www.kikt.top/tags/exists/">exists</a>
    
    <a href="http://www.kikt.top/tags/faq/">faq</a>
    
    <a href="http://www.kikt.top/tags/fastlane/">fastlane</a>
    
    <a href="http://www.kikt.top/tags/ffi/">ffi</a>
    
    <a href="http://www.kikt.top/tags/ffmpeg/">ffmpeg</a>
    
    <a href="http://www.kikt.top/tags/flexmark/">flexmark</a>
    
    <a href="http://www.kikt.top/tags/flutter/">flutter</a>
    
    <a href="http://www.kikt.top/tags/flutter-web/">flutter-web</a>
    
    <a href="http://www.kikt.top/tags/focus/">focus</a>
    
    <a href="http://www.kikt.top/tags/focusNode/">focusNode</a>
    
    <a href="http://www.kikt.top/tags/form/">form</a>
    
    <a href="http://www.kikt.top/tags/framework/">framework</a>
    
    <a href="http://www.kikt.top/tags/github/">github</a>
    
    <a href="http://www.kikt.top/tags/go/">go</a>
    
    <a href="http://www.kikt.top/tags/golang/">golang</a>
    
    <a href="http://www.kikt.top/tags/gradle/">gradle</a>
    
    <a href="http://www.kikt.top/tags/http/">http</a>
    
    <a href="http://www.kikt.top/tags/iOS/">iOS</a>
    
    <a href="http://www.kikt.top/tags/ide/">ide</a>
    
    <a href="http://www.kikt.top/tags/idea/">idea</a>
    
    <a href="http://www.kikt.top/tags/index/">index</a>
    
    <a href="http://www.kikt.top/tags/inside/">inside</a>
    
    <a href="http://www.kikt.top/tags/ios/">ios</a>
    
    <a href="http://www.kikt.top/tags/java/">java</a>
    
    <a href="http://www.kikt.top/tags/jenkins/">jenkins</a>
    
    <a href="http://www.kikt.top/tags/jetbrains/">jetbrains</a>
    
    <a href="http://www.kikt.top/tags/jsdelivr/">jsdelivr</a>
    
    <a href="http://www.kikt.top/tags/json/">json</a>
    
    <a href="http://www.kikt.top/tags/json_serializable/">json_serializable</a>
    
    <a href="http://www.kikt.top/tags/junit/">junit</a>
    
    <a href="http://www.kikt.top/tags/library/">library</a>
    
    <a href="http://www.kikt.top/tags/live-template/">live-template</a>
    
    <a href="http://www.kikt.top/tags/loadmore/">loadmore</a>
    
    <a href="http://www.kikt.top/tags/log/">log</a>
    
    <a href="http://www.kikt.top/tags/mac/">mac</a>
    
    <a href="http://www.kikt.top/tags/macos/">macos</a>
    
    <a href="http://www.kikt.top/tags/maven/">maven</a>
    
    <a href="http://www.kikt.top/tags/mysql/">mysql</a>
    
    <a href="http://www.kikt.top/tags/navigationbar/">navigationbar</a>
    
    <a href="http://www.kikt.top/tags/navigator/">navigator</a>
    
    <a href="http://www.kikt.top/tags/ndk/">ndk</a>
    
    <a href="http://www.kikt.top/tags/nginx/">nginx</a>
    
    <a href="http://www.kikt.top/tags/oc/">oc</a>
    
    <a href="http://www.kikt.top/tags/opencv/">opencv</a>
    
    <a href="http://www.kikt.top/tags/poi/">poi</a>
    
    <a href="http://www.kikt.top/tags/pub/">pub</a>
    
    <a href="http://www.kikt.top/tags/python/">python</a>
    
    <a href="http://www.kikt.top/tags/retrofit/">retrofit</a>
    
    <a href="http://www.kikt.top/tags/route/">route</a>
    
    <a href="http://www.kikt.top/tags/server/">server</a>
    
    <a href="http://www.kikt.top/tags/so/">so</a>
    
    <a href="http://www.kikt.top/tags/spp/">spp</a>
    
    <a href="http://www.kikt.top/tags/sprintboot/">sprintboot</a>
    
    <a href="http://www.kikt.top/tags/swift/">swift</a>
    
    <a href="http://www.kikt.top/tags/tap/">tap</a>
    
    <a href="http://www.kikt.top/tags/thymeleaf/">thymeleaf</a>
    
    <a href="http://www.kikt.top/tags/tips/">tips</a>
    
    <a href="http://www.kikt.top/tags/toast/">toast</a>
    
    <a href="http://www.kikt.top/tags/transition/">transition</a>
    
    <a href="http://www.kikt.top/tags/ui/">ui</a>
    
    <a href="http://www.kikt.top/tags/utf8/">utf8</a>
    
    <a href="http://www.kikt.top/tags/yield/">yield</a>
    
    <a href="http://www.kikt.top/tags/%E4%BA%8C%E8%BF%9B%E5%88%B6/">二进制</a>
    
    <a href="http://www.kikt.top/tags/%E4%BA%A4%E5%8F%89/">交叉</a>
    
    <a href="http://www.kikt.top/tags/%E4%BA%A4%E5%8F%89%E7%BC%96%E8%AF%91/">交叉编译</a>
    
    <a href="http://www.kikt.top/tags/%E4%BB%8B%E7%BB%8D/">介绍</a>
    
    <a href="http://www.kikt.top/tags/%E4%BB%A3%E7%A0%81%E8%A7%84%E8%8C%83/">代码规范</a>
    
    <a href="http://www.kikt.top/tags/%E5%86%B2%E7%AA%81/">冲突</a>
    
    <a href="http://www.kikt.top/tags/%E5%8A%A8%E6%80%81/">动态</a>
    
    <a href="http://www.kikt.top/tags/%E5%8F%91%E5%B8%83/">发布</a>
    
    <a href="http://www.kikt.top/tags/%E5%8F%AF%E6%89%A7%E8%A1%8C/">可执行</a>
    
    <a href="http://www.kikt.top/tags/%E5%9B%BE%E5%BA%8A/">图床</a>
    
    <a href="http://www.kikt.top/tags/%E5%9F%8E%E5%B8%82/">城市</a>
    
    <a href="http://www.kikt.top/tags/%E5%A4%A7%E6%96%87%E4%BB%B6/">大文件</a>
    
    <a href="http://www.kikt.top/tags/%E5%B7%A5%E5%85%B7/">工具</a>
    
    <a href="http://www.kikt.top/tags/%E5%B7%B2%E6%9C%89%E9%A1%B9%E7%9B%AE/">已有项目</a>
    
    <a href="http://www.kikt.top/tags/%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83/">开发环境</a>
    
    <a href="http://www.kikt.top/tags/%E6%80%BB%E7%BB%93/">总结</a>
    
    <a href="http://www.kikt.top/tags/%E6%85%A2/">慢</a>
    
    <a href="http://www.kikt.top/tags/%E6%89%93%E5%8C%85/">打包</a>
    
    <a href="http://www.kikt.top/tags/%E6%89%AB%E7%A0%81/">扫码</a>
    
    <a href="http://www.kikt.top/tags/%E6%8F%92%E4%BB%B6/">插件</a>
    
    <a href="http://www.kikt.top/tags/%E6%96%87%E6%A1%A3/">文档</a>
    
    <a href="http://www.kikt.top/tags/%E6%A8%A1%E6%9D%BF/">模板</a>
    
    <a href="http://www.kikt.top/tags/%E6%B8%B2%E6%9F%93/">渲染</a>
    
    <a href="http://www.kikt.top/tags/%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/">源码解析</a>
    
    <a href="http://www.kikt.top/tags/%E7%81%B0%E5%BA%A6/">灰度</a>
    
    <a href="http://www.kikt.top/tags/%E7%82%B9%E5%87%BB/">点击</a>
    
    <a href="http://www.kikt.top/tags/%E7%84%A6%E7%82%B9/">焦点</a>
    
    <a href="http://www.kikt.top/tags/%E7%88%AC%E8%99%AB/">爬虫</a>
    
    <a href="http://www.kikt.top/tags/%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86/">状态管理</a>
    
    <a href="http://www.kikt.top/tags/%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE/">百度地图</a>
    
    <a href="http://www.kikt.top/tags/%E7%BC%96%E7%A0%81/">编码</a>
    
    <a href="http://www.kikt.top/tags/%E7%BC%96%E7%A8%8B%E6%8A%80%E5%B7%A7/">编程技巧</a>
    
    <a href="http://www.kikt.top/tags/%E7%BC%96%E8%AF%91/">编译</a>
    
    <a href="http://www.kikt.top/tags/%E7%BF%BB%E8%AF%91/">翻译</a>
    
    <a href="http://www.kikt.top/tags/%E8%93%9D%E7%89%99/">蓝牙</a>
    
    <a href="http://www.kikt.top/tags/%E8%A1%A8%E5%8D%95/">表单</a>
    
    <a href="http://www.kikt.top/tags/%E8%B7%AF%E7%94%B1/">路由</a>
    
    <a href="http://www.kikt.top/tags/%E8%BF%87%E5%9C%BA%E5%8A%A8%E7%94%BB/">过场动画</a>
    
    <a href="http://www.kikt.top/tags/%E9%9A%90%E7%A7%81/">隐私</a>
    
</div>
    </section>

    
<section class="widget">
    <h3 class="widget-title">友情链接</h3>
    <ul class="widget-list">
        
        <li>
            <a target="_blank" href="https://github.com/Caijinglong" title="我的Github">我的Github</a>
        </li>
        
        <li>
            <a target="_blank" href="https://flutter.dev" title="flutter 官网">flutter 官网</a>
        </li>
        
    </ul>
</section>


    <section class="widget">
        <h3 class="widget-title">其它</h3>
        <ul class="widget-list">
            <li><a href="http://www.kikt.top/index.xml">文章 RSS</a></li>
        </ul>
    </section>
</div>
        </div>
    </div>
</div>
<footer id="footer">
    <div class="container">
        <div>
            <p>如果我的blog对您有帮助,而您愿意捐赠 😆, 可以用下面的二维码</p>
            <img style="width:5rem;" src="https://dev.azure.com/cjlspy/844861b8-ee45-48a3-b430-b974684baaaa/_apis/git/repositories/bf4da1c1-1cfa-4f54-8a75-745cce2b737c/items?versionDescriptor%5Bversion%5D=master&versionDescriptor%5BversionOptions%5D=0&versionDescriptor%5BversionType%5D=0&resolveLfs=true&%24format=octetStream&api-version=5.0&path=%2F20190424141834.png"/>
            <img style="width:5rem; padding-left: 2rem;" 
            src="https://dev.azure.com/cjlspy/844861b8-ee45-48a3-b430-b974684baaaa/_apis/git/repositories/bf4da1c1-1cfa-4f54-8a75-745cce2b737c/items?versionDescriptor%5Bversion%5D=master&versionDescriptor%5BversionOptions%5D=0&versionDescriptor%5BversionType%5D=0&resolveLfs=true&%24format=octetStream&api-version=5.0&path=%2F20190424141931.png"/>
            <img style="width:5rem; padding-left: 2rem;" 
            src="https://dev.azure.com/cjlspy/844861b8-ee45-48a3-b430-b974684baaaa/_apis/git/repositories/bf4da1c1-1cfa-4f54-8a75-745cce2b737c/items?versionDescriptor%5Bversion%5D=master&versionDescriptor%5BversionOptions%5D=0&versionDescriptor%5BversionType%5D=0&resolveLfs=true&%24format=octetStream&api-version=5.0&path=%2F20190424142013.png"/>
        </div>
        &copy; 2018 <a href="http://www.kikt.top">caijinglong的博客 By caijinglong</a>.
        Powered by <a rel="nofollow noreferer noopener" href="https://gohugo.io" target="_blank">Hugo</a>.
        <a href="http://www.flysnow.org/" target="_blank">Theme</a> based on <a href="https://github.com/rujews/maupassant-hugo" target="_blank">maupassant</a>.<br/>
        本站所有内容基于<a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh" style="color:coral">CC4.0</a>协议发布,需要转载必须署名
        <br/>
        如果有问题可以<a href="mailto:cjl_spy@163.com">email联系我</a>
        <br/>
        京ICP备18038473号-1
        
    </div>
</footer>


    <script type="text/javascript" src="/js/prism.js" async="true"></script>
    <script type="text/javascript">
    
    (function(){
        $("pre code").parent().addClass("line-numbers")
    }())

    window.MathJax = {
        tex2jax: {
            inlineMath: [ ['$','$'] ],
            processEscapes: true
        }
    };
    </script>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML' async></script>

<a id="rocket" href="#top"></a>
<script type="text/javascript" src="/js/totop.js?v=0.0.0" async=""></script>



<script type="text/javascript" src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" async></script>




</body>
</html>
